package top.littlejiang.onlinexam.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import top.littlejiang.onlinexam.common.base.BaseServiceImpl;
import top.littlejiang.onlinexam.common.base.BusinessException;
import top.littlejiang.onlinexam.common.base.Constant;
import top.littlejiang.onlinexam.common.utils.DateUtils;
import top.littlejiang.onlinexam.common.utils.JSONUtils;
import top.littlejiang.onlinexam.common.utils.JWTUtils;
import top.littlejiang.onlinexam.common.utils.RedisUtils;
import top.littlejiang.onlinexam.entity.*;
import top.littlejiang.onlinexam.mapper.OlexamStuAnswerMapper;
import top.littlejiang.onlinexam.service.OlexamStuAnswerService;
import top.littlejiang.onlinexam.service.OlexamStuScoreService;
import top.littlejiang.onlinexam.service.OlexamTaskService;
import top.littlejiang.onlinexam.vo.AutoCheckVO;
import top.littlejiang.onlinexam.vo.CheckVO;
import top.littlejiang.onlinexam.vo.SubmitPaperVO;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生答卷 服务实现类
 * </p>
 *
 * @author chen
 * @since 2021-03-11
 */
@Service
public class OlexamStuAnswerServiceImpl extends BaseServiceImpl<OlexamStuAnswerMapper, OlexamStuAnswer> implements OlexamStuAnswerService {

    @Autowired
    OlexamTaskService taskService;
    @Autowired
    OlexamStuScoreService stuScoreService;

    /**
     * 学生提交试卷
     * @param vo
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    @Override
    public void submitPaper(SubmitPaperVO vo) throws InstantiationException, IllegalAccessException {

        RedisUtils.setString("paper-"+vo.getExam().getExamUuid() + '-' + JWTUtils.getUserId(), JSONUtils.beanToJson(vo));

        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("fk_exam_uuid", vo.getExam().getExamUuid());
        wrapper.eq("fk_user_id", JWTUtils.getUserId());
        List list = list(wrapper);

        if (!CollectionUtils.isEmpty(list)){
            return;
        }

        OlexamExam exam = vo.getExam();
        List<OlexamStuAnswer> stuAnswers = new ArrayList<>();
        vo.getAllQuestions().stream().forEach(item -> {
            OlexamStuAnswer oneEntity = new OlexamStuAnswer();
            oneEntity.setFkExamUuid(exam.getExamUuid())
                    .setFkUserId(JWTUtils.getUserId())
                    .setFkQuestionId(item.getId())
                    .setIsCompress(0)
                    .setStatus(0)
                    .setIsDel(0)
                    .setScore(0.0);
            if (item.getType().equals(Constant.SHORT_ANSWER_QUESTION)){
                oneEntity.setAnswerText(item.getAnswerText());
                oneEntity.setAnswerHtml(item.getAnswerHtml());
            }else{
                oneEntity.setAnswerText(item.getAnswer());
            }
            stuAnswers.add(oneEntity);
        });
        savePaper(stuAnswers);


        String cornStr = DateUtils.toCornString(new Date(System.currentTimeMillis() + 90 * 1000));

        Map<String, Object> param = new HashMap<>(2);
        param.put("fk_exam_uuid", exam.getExamUuid());
        param.put("fk_user_id", String.valueOf(JWTUtils.getUserId()));

        OlexamTask task = new OlexamTask();
        task.setTaskType(Constant.AUTO_CHECK_PAPER);
        task.setTaskCorn(cornStr);
        task.setTaskParams(JSONUtils.beanToJson(param));
        task.setParamMap(param);

        taskService.addTask(task);

    }

    /**
     * 保存学生作答
     *
     * @param stuAnswers
     */
    @Override
    public void savePaper(List<OlexamStuAnswer> stuAnswers) {

        saveOrUpdateBatch(stuAnswers, stuAnswers.size());
    }

    /**
     * 获取学生答卷 -> 自动阅卷
     *
     * @param userId
     * @param examUuid
     * @return
     */
    @Override
    public List<AutoCheckVO> selectForAuto(Integer userId, String examUuid) {
        return baseMapper.selectForAuto(userId, examUuid);
    }

    /**
     * 查询成绩
     *
     * @param examUuid
     */
    @Override
    public OlexamStuScore queryScore(String examUuid, Integer userId) {
        OlexamStuScore stuScore = stuScoreService.queryOne(examUuid, userId);
        if (Objects.isNull(stuScore)){
            return null;
        }
        if (stuScore.getIsCorrected() == 1){
            return stuScore;
        }else{
            OlexamStuScore stuScore1 = computeScore(stuScore, examUuid, userId);
            if (Objects.isNull(stuScore1)){
                throw new BusinessException("当前试卷未批阅完成，无法查询成绩！");
            }else{
                return stuScore1;
            }
        }
    }

    /**
     * 计算总得分
     *
     * @param examUuid
     * @param userId
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public OlexamStuScore computeScore(OlexamStuScore stuScore, String examUuid, Integer userId) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("fk_user_id",userId);
        wrapper.eq("fk_exam_uuid", examUuid);
        wrapper.eq("is_del", 0);
        List<OlexamStuAnswer> answers = list(wrapper);
        List<OlexamStuAnswer> noCheck = answers.stream().filter(OlexamStuScore -> OlexamStuScore.getStatus() == 0).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(noCheck)){
            return null;
        }
        double totalScore = answers.stream().mapToDouble(OlexamStuAnswer::getScore).sum();

        stuScore.setTotalScore(totalScore);
        stuScore.setIsCorrected(1);
        stuScoreService.updateById(stuScore);
        return stuScore;
    }

    /**
     * 查询一条待批阅数据
     *
     * @param examUuid
     * @return
     */
    @Override
    public CheckVO queryToCheck(String examUuid) {
        CheckVO checkVO = getBaseMapper().queryToCheck(examUuid);
        if (Objects.isNull(checkVO)){
            throw new BusinessException("所有题目已批阅完成！");
        }
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("fk_exam_uuid", examUuid);
        wrapper.isNull("grade_id");
        wrapper.isNotNull("answer_html");
        wrapper.eq("status", 0);
        int total = this.count(wrapper);
        checkVO.setTotal(total);
        return checkVO;
    }

    /**
     * 提交一条批阅数据
     *
     * @param stuAnswer
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void submitCheck(OlexamStuAnswer stuAnswer) {
        stuAnswer.setStatus(1);
        stuAnswer.setGradeId(JWTUtils.getUserId());
        stuAnswer.setUpdateTime(DateUtils.getTime());
        getBaseMapper().updateById(stuAnswer);
    }

    /**
     * 学生成绩 按题目类型 统计
     *
     * @param examUuid
     * @return
     */
    @Override
    public Map<String, Object> addUp(String examUuid) {
        Integer userId = JWTUtils.getUserId();
        List<OlexamQuestions> questions = getBaseMapper().selectByQuestions(examUuid, userId);
        Map<String, List<OlexamQuestions>> collect = questions.stream().collect(Collectors.groupingBy(OlexamQuestions::getType));
        Map<String, Object> rst = new HashMap<>(4);
        for (String type : collect.keySet()){
            List<OlexamQuestions> temp = collect.get(type);
            double sum = temp.stream().mapToDouble(OlexamQuestions::getScore).sum();
            rst.put(type, sum);
        }
        return rst;
    }


}
